﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using StockFinder.Model;

namespace StockFinder.Services.ChartPatterns
{
    public class WeeklyFlatBaseChartPattern : IChartPattern
    {
        private readonly decimal _BaseDepth = 0.15M;
        private readonly int _MinimumWeeklyCoverage = 5;

        public WeeklyFlatBaseChartPattern()
        {
            //use defaults
        }

        public WeeklyFlatBaseChartPattern(decimal baseDepth, int minimumWeeklyCoverage)
        {
            _BaseDepth = baseDepth;
            _MinimumWeeklyCoverage = minimumWeeklyCoverage;
        }

        #region IChartPattern Members

        public ChartPatternResult Apply(Symbol symbol)
        {
            FlatBaseChartPatternResult result = new FlatBaseChartPatternResult();

            result.Symbol = symbol;

            decimal latestWeeklyHigh = 0;
            decimal maximumHigh = 0;
            decimal maximumLow = 0;
            decimal depth = 0;
            int weekCount = 0;
            int baseLength = 0;

            //check we have (enough) prices
            if (symbol.WeeklyPrices != null && symbol.WeeklyPrices.Count > _MinimumWeeklyCoverage)
            {
                #region Setup initial data

                latestWeeklyHigh = symbol.WeeklyPrices[0].GetWeeklyHigh();
                maximumHigh = symbol.WeeklyPrices[0].GetWeeklyHigh();
                maximumLow = symbol.WeeklyPrices[0].GetWeeklyLow();

                #endregion

                #region Loop prices

                //loop prices
                foreach (WeeklyPrice weeklyPrice in symbol.WeeklyPrices)
                {
                    //new week
                    weekCount++;

                    #region Validate week prices

                    //check not empty prices
                    if (weeklyPrice.GetWeeklyOpen() == 0)
                    {
                        break;
                    }

                    #endregion

                    #region Set week high and low

                    //do we have a new peak?
                    if (weeklyPrice.GetWeeklyHigh() > maximumHigh)
                    {
                        //yes
                        maximumHigh = weeklyPrice.GetWeeklyHigh();
                    }

                    //do we have a new low point?
                    if (weeklyPrice.GetWeeklyLow() < maximumLow)
                    {
                        //yes
                        maximumLow = weeklyPrice.GetWeeklyLow();
                    }

                    #endregion

                    #region Calculate the base depth

                    //calculate depth
                    depth = (maximumHigh - maximumLow) / maximumHigh;

                    #endregion

                    #region Flat base check

                    //have we breached base depth?
                    if (depth > _BaseDepth)
                    {
                        //yes so check base length
                        result.DoesFit = (baseLength >= _MinimumWeeklyCoverage);

                        //need to quit as depth breached
                        break;
                    }
                    else
                    {
                        //no so check if this week was a valid base start
                        if (weeklyPrice.GetWeeklyHigh() == maximumHigh)
                        {
                            //yes so determine new base length
                            baseLength = weekCount;
                        }
                    }

                    #endregion

                    result.BaseHigh = maximumHigh;
                    result.BaseLow = maximumLow;
                }

                #endregion
            }

            result.BaseLength = baseLength;

            return result;
        }

        #endregion
    }
}
